package com.easylinkin.linkappapi.common.utils.async;

import cn.hutool.core.collection.CollectionUtil;
import com.easylinkin.linkappapi.common.service.OSSService;
import com.easylinkin.linkappapi.common.utils.excel.RedisAsyResultData;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import org.apache.poi.ss.formula.functions.T;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class AsyncUtil implements ApplicationContextAware {

  static Logger LOG = LoggerFactory.getLogger(AsyncUtil.class);
  public static ExecutorService executor = Executors.newFixedThreadPool(40);
  public static ScheduledExecutorService ex = Executors.newScheduledThreadPool(1);
  static List<String> keys = new ArrayList<>();
  static boolean scheduleIsStart = false;

  private static OSSService ossService;

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    ossService = applicationContext.getBean(OSSService.class);
  }

  public static RedisTemplate<String, RedisAsyResultData> getRedisTemplate() {
    return SpringUtils.getBean("redisTemplate", RedisTemplate.class);
  }

  static void updateKeyLiveTime() {
    if (!scheduleIsStart) {
      // 更新redis中缓存的过期时间
      ex.scheduleAtFixedRate(() -> {
        try {
          LOG.info("----- update AsyncResult keys length:{} -----",
              keys.size());
          if (CollectionUtil.isNotEmpty(keys)) {
            List<RedisAsyResultData> multiGet =
                getRedisTemplate().opsForValue().multiGet(keys);
            for (RedisAsyResultData result : multiGet) {
              if (result != null) {
                String key = result.getRedisKey();
                getRedisTemplate()
                    .expire(key, 5, TimeUnit.MINUTES);
              }
            }
          }
        } catch (Exception e) {
          scheduleIsStart = false;
          LOG.error(e.getMessage(), e);
        }
      }, 1, 3, TimeUnit.MINUTES);
      scheduleIsStart = true;
    }
  }

  public static RedisAsyResultData submitTask(String key, Supplier supplier) {
    RedisAsyResultData rs = new RedisAsyResultData();
    rs.setSuccess(false);
    rs.setRedisKey(key);
    rs.setDone(0);
    rs.setTotal(100);
    setToRedis(rs, key);
    if (!keys.contains(key)) {
      keys.add(key);
    }
    String finalKey = key;
    executor.submit(() -> {
      String msg = null;
      try {
        Object o = supplier.get();
        rs.setData(o);
        rs.setFlag(true);
      } catch (Exception e) {
        rs.setFlag(false);
        msg = e.getMessage();
        LOG.error(e.getMessage(), e);
      }
      rs.setSuccess(true);
      rs.setDone(rs.getTotal());
      if (null != msg) {
        rs.setError(msg);
      }
      keys.remove(finalKey);
      setToRedis(rs, finalKey);
    });
    updateKeyLiveTime();
    return rs;
  }


  /**
   * 将上传服务器这一步放到工具类中,业务代码只处理业务
   * @param key
   * @return
   */
//  public static RedisAsyResultData newSubmitTask(String key, Supplier<Map<String, Object>> supplier) {
//    RedisAsyResultData rs = new RedisAsyResultData();
//    rs.setSuccess(false);
//    rs.setRedisKey(key);
//    rs.setDone(0);
//    rs.setTotal(100);
//    setToRedis(rs, key);
//    if (!keys.contains(key)) {
//      keys.add(key);
//    }
//    executor.submit(() -> {
//      String msg = null;
//      try {
//        //返回数据，和excel模板路径
//        Map<String, Object> map = supplier.get();
//        String filePath = createExcel(map);
//        String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
//        String resultFilename = Utils.originalKey(key) + today + ".xls";
//        byte[] bytes = AsyncUtil.FileToByte(filePath);
//        ossService.uploadTempFile(bytes, resultFilename);
//        rs.setData(resultFilename);
//        rs.setDone(rs.getTotal());
//      } catch (Exception e) {
//        msg = e.getMessage();
//        LOG.error(e.getMessage(), e);
//      }
//      rs.setSuccess(true);
//      if (null != msg) {
//        rs.setError(msg);
//      }
//      keys.remove(key);
//      setToRedis(rs, key);
//    });
//    updateKeyLiveTime();
//    return rs;
//  }


  /**
   * 将上传服务器这一步放到工具类中,业务代码只处理业务
   * 与上一个方法不同，改方法直接返回文件路径。不使用模板(easyPoi)
   * @param key
   * @return
   */
//  public static RedisAsyResultData newSubmitTask1(String key, Supplier<String> supplier) {
//    RedisAsyResultData rs = new RedisAsyResultData();
//    rs.setSuccess(false);
//    rs.setRedisKey(key);
//    rs.setDone(0);
//    rs.setTotal(100);
//    setToRedis(rs, key);
//    if (!keys.contains(key)) {
//      keys.add(key);
//    }
//    executor.submit(() -> {
//      String msg = null;
//      try {
//        //返回数据，和excel模板路径
//        String filePath = supplier.get();
////        String filePath = createExcel(map);
//        String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
//        String resultFilename = Utils.originalKey(key) + today + ".xls";
//        byte[] bytes = AsyncUtil.FileToByte(filePath);
//        ossService.uploadTempFile(bytes, resultFilename);
//        rs.setData(resultFilename);
//        rs.setDone(rs.getTotal());
//      } catch (Exception e) {
//        msg = e.getMessage();
//        LOG.error(e.getMessage(), e);
//      }
//      rs.setSuccess(true);
//      if (null != msg) {
//        rs.setError(msg);
//      }
//      keys.remove(key);
//      setToRedis(rs, key);
//    });
//    updateKeyLiveTime();
//    return rs;
//  }

//  @SneakyThrows
//  public static String createExcel(Map<String,Object> data){
//    TemplateExportParams params = new TemplateExportParams(new ClassPathResource((String) data.get("path")).getPath()
//        , false);
//    Workbook book = ExcelExportUtil.exportExcel(params, data);
//    File tempFile = File.createTempFile(System.currentTimeMillis() + "", ".xlsx");
//    FileOutputStream outputStream = new FileOutputStream(tempFile);
//    book.write(outputStream);
//    outputStream.close();
//    return tempFile.getAbsolutePath();
//  }


  private static void setToRedis(RedisAsyResultData result, String redisKey) {
    getRedisTemplate().opsForValue().set(redisKey, result, 5, TimeUnit.MINUTES);
  }

  public static RedisAsyResultData getResult(String key) {
    RedisAsyResultData excelResult =
        getRedisTemplate().opsForValue().get(key);
    if (null != excelResult) {
      return excelResult;
    }
    return null;
  }

  public static void saveResult(String key, RedisAsyResultData result) {
    setToRedis(result, key);
  }

  public static byte[] FileToByte(String filePath) throws Exception{
    FileInputStream fis = null;
    BufferedInputStream bis = null;
    try {
      fis = new FileInputStream(filePath);
      bis = new BufferedInputStream(fis);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      int c = bis.read();
      while (c != -1) {
        // 数据存储到ByteArrayOutputStream中
        baos.write(c);
        c = bis.read();
      }
      fis.close();
      bis.close();
      // 转换成二进制
      byte[] bytes = baos.toByteArray();
      return bytes;
    }catch (Exception e){
      e.printStackTrace();
      throw e;
    }finally {
      try {
        if (fis != null ) {
          fis.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
        throw e;
      } finally {
        try {
          if (bis != null ) {
            bis.close();
          }
        } catch (IOException e) {
          e.printStackTrace();
          throw e;
        }
      }
    }
  }
}
